package cantools

import (
	"bufio"
	"fmt"
	"gitee.com/CoolguyHolmes/socketcan-fd"
	"os"
)

func (c *Can) Log() {
	cnt := 0

	buf := bufio.NewWriter(c.fd)
	defer buf.Flush()
	for frame := range c.logCh {

		str := c.serialization.Serialize(frame)
		cnt += len(str)
		buf.WriteString(str)
		buf.Flush()
	}
}

func Constructor() {
	fd.Constructor()
}

func FrameParser(frame *fd.RawFrame) {
	fmt.Printf("Interface: %d, ArbId: %X, Dlc: %d, Time: %7vms, Data: %X\n", frame.Interface,
		frame.ArbId,
		frame.Dlc,
		frame.Time,
		frame.Data[:frame.Dlc])
}

func Engine(opts ...canInterfaceOptions) *Can {
	o := newCanInterfaceOption(opts)

	fileHandle, err := os.OpenFile(o.mirrorPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	size := len(o.canIfsName)
	canIfChs := make([]chan *fd.RawFrame, 0, size+1)
	for i := 0; i <= size; i++ {
		canIfChs = append(canIfChs, make(chan *fd.RawFrame, 1))
	}
	canInstance := &Can{
		canIfs:        nil,
		rCh:           make(chan *fd.RawFrame, 300),
		mirror:        o.mirror,
		fd:            fileHandle,
		logCh:         make(chan *fd.RawFrame, 200),
		hookList:      nil,
		serialization: o.serialization,
		canIfChs:      canIfChs,
		switchs:       make([]bool, size+1),
		indexWhoIsAll: uint32(size),
		mirrorPath:    o.mirrorPath,
	}
	go canInstance.Log()

	// 先读数据再初始化

	canIfs := make([]fd.Interface, len(o.canIfsName))
	canInstance.canIfs = canIfs
	for i, v := range o.canIfsName {
		If, err := fd.NewRawFdInterface(v)
		if err != nil {
			panic(fmt.Sprintf("create Interface %v err: %s", v, err))
		}
		canIfs[i] = If
		go func(index uint32, c *Can) {
			I := c.canIfs[index]
			rCh := c.rCh
			var f *fd.RawFrame
			for {
				f, err = I.RecvFrame()
				if err != nil {
					fmt.Println("recv Can frame err:", err)
					continue
				}

				rCh <- f
				if c.mirror {
					c.logCh <- f
				}
				for _, vf := range c.hookList {
					vf(f)
				}
			}
		}(uint32(i), canInstance)
	}

	go func(c *Can) {
		all := c.indexWhoIsAll
		for f := range c.rCh {
			//go func(c *Can, f *fd.RawFrame) {
			idx := f.Interface
			if c.switchs[all] {
				c.switchs[all] = false
				c.canIfChs[all] <- f
			}
			if c.switchs[idx] {
				c.switchs[idx] = false
				c.canIfChs[idx] <- f
			}
			//}(c, f)

		}
	}(canInstance)
	return canInstance
}

// Recv 供给客户端调用的, 表征从通道到达上位机
func (c *Can) Recv(Interface int32) *fd.RawFrame {
	c.switchs[Interface] = true
	return <-c.canIfChs[Interface]
}

func (c *Can) RecvAll() *fd.RawFrame {
	c.switchs[c.indexWhoIsAll] = true
	return <-c.canIfChs[c.indexWhoIsAll]
}

// Send 供给客户端调用的, 表征从上位机到达通道
func (c *Can) Send(frame *fd.RawFrame) error {
	c.logCh <- frame
	return c.canIfs[frame.Interface].SendFrame(frame)
}

func (c *Can) EnableMirror() {
	c.mirror = true
}

func (c *Can) DisableMirror() {
	c.mirror = false
}

//RegisterLogFile 修改日志目录并打开镜像功能
func (c *Can) RegisterLogFile(fileName string) {
	fileHandle, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		panic(err)
	}
	c.fd.Close()
	c.mirrorPath = fileName
	c.fd = fileHandle
	c.EnableMirror()
	return
}

func (c *Can) RegisterHook(a func(*fd.RawFrame)) {
	c.hookList = append(c.hookList, a)
	return
}

func (c *Can) RegisterSerialization(serialization Serialization) {
	c.serialization = serialization
	return
}

func (c *Can) Close() {
	c.fd.Close()
	for _, If := range c.canIfs {
		If.Close()
	}
}
